<?php
/**
 * 유틸리티 - IP
 *
 * <code>
 * $utilIp = utilIp::getInstance();
 * $sClientIP = $utilIp->getClientIP();
 * </code>
 *
 * @package util
 *
 * @author jylee3@simplexi.com
 * @version 1.0
 */
class utilIp
{
    /**
     * utilIp Instance
     *
     * <code>
     * $utilIp = utilIp::getInstance();
     * </code>
     *
     * @return    utilIp
     */
    public static function getInstance()
    {
        return utilSplClass::load('utilIp');
    }

    public function __construct() {}

    /**
     * Getting... Client IP
     *
     * <code>
     * $utilIp = utilIp::getInstance();
     * $sClientIP = $utilIp->getClientIP();
     * </code>
     *
     * @return    String    클라이언트 IP주소 문자열
     */
    public function getClientIP()
    {
        /* check ip from share internet */
        if (isset($_SERVER['HTTP_CLIENT_IP']))    return $_SERVER['HTTP_CLIENT_IP'];

        /* to check ip is pass from proxy */
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])
            && preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $aMatches)) {

            /* make sure we dont pick up an internal IP defined by RFC1918 */
            foreach ($aMatches[0] as $sIp) {
                if (!preg_match("#^(10|172\.16|192\.168)\.#", $sIp)) {
                    return $sIp;

                    break;
                }
            }
        }

        /* default httpd client remote ip */
        return isset($_SERVER['REMOTE_ADDR'])? $_SERVER['REMOTE_ADDR'] : false;
    }

    /**
     * Getting... Client Port
     *
     * <code>
     * $utilIp = utilIp::getInstance();
     * $iClientPort = $utilIp->getClientPort();
     * </code>
     *
     * @return    Integer    클라이언트 포트
     */
    public function getClientPort()
    {
        return $_SERVER['REMOTE_PORT'];
    }

    /**
     * Getting... IP Masking
     *
     * <code>
     * $utilIp = utilIp::getInstance();
     * $sNetMask = $utilIp->getIpMasking('127.0.0.1', '255.255.255.0')
     * </code>
     *
     * @param    String    $sIp    마스킹 대상 IP주소
     * @param    String    $sMask    넷마스크
     *
     * @return    String    마스킹 된 IP주소
     */
    public function getIpMasking($sIp, $sMask='255.255.255.0')
    {
        $iIp = ip2long($sIp);
        $iMask = ip2long($sMask);
        $iMasking = $iIp&$iMask;

        return long2ip(sprintf("%u", $iMasking));
    }

    /**
     * Is... IP Block Check
     *
     * <code>
     * $utilIp = utilIp::getInstance();
     * $bBlock = $utilIp->isBlockingIp('127.0.0.0', '127.0.0.1');
     * $bBlock = $utilIp->isBlockingIp(array('127.0.0.1', '127.0.0.2'), '127.0.0.1');
     * </code>
     *
     * @param    Mixed    $mBlockIp    차단 IP주소/네트워크ID 또는 그 목록
     * @param    String    $sIP    대상 IP주소, 값을 지정하지 않을경우 클라이언트 IP주소
     *
     * @return    Boolean    차단 대상이면 true, 사단 대상이 아닐 경우 false
     */
    public function isBlockingIp($mBlockIp, $sIP=null)
    {
        if (is_null($sIP))    $sIP = $this->getClientIP();

        if (is_array($mBlockIp)) {
            foreach ($mBlockIp as $sBlockIP) {
                if($this->isBlockingIpAndMask($sBlockIP, $sIP))    return true;
            }
        } else {
            if($this->isBlockingIpAndMask($mBlockIp, $sIP))    return true;
        }

        return false;
    }

    protected function isBlockingIpAndMask($sBlockIP, $sIpAndMask)
    {
        $iIpAndMask = ip2long($sIpAndMask);

        $iBlockIP = ip2long($sBlockIP);
        $iBlockMasking = $iIpAndMask&$iBlockIP;
        $iIPLastBit = $iBlockIP%256;

        /* ip check */
        if($iIPLastBit==0 && $iIpAndMask==$iBlockMasking)    return true;

        /* masking check */
        if($iBlockIP==$iBlockMasking)    return true;

        return false;
    }
}
